﻿using System;
using System.ComponentModel;
using System.Text;
using System.Windows.Forms;
using System.IO;
using Microsoft.Win32;
using System.Timers;        //系统时钟
using System.Security.Cryptography; // 添加这一行
using System.Runtime.InteropServices;
using System.Collections;
using System.Data;
using System.IO.Ports;
using System.Threading;
using win_iap_ymodem;
using System.Drawing;
using System.Threading.Tasks;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct _stUartRecMsg
{
    public int u16len;             // 起始地址
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)]
    public byte[] u8DataBuf;                // 数据

}
public struct _StRS485UpgeradMsg
{
    public byte WaitIntoUpgradeModeCmdAckFlag;      // 等待进入升级模式指令应答标志
    public byte WaitUpgradeStartCmdAckFlag;         // 等待升级开始指令应答标志
    public byte WaitUpgradeFileTransferCmdAckFlag;  // 等待升级文件传输指令应答标志
    public byte WaitUpgradeEndCmdAckFlag;           // 等待升级结束指令应答标志

    public ushort u16IntoUpgradeModeCmdAckFlag;     // 进入升级模式指令应答标志
    public ushort u16UpgradeStartCmdAckFlag;        // 升级开始指令应答标志
    public ushort u16UpgradeFileTransferCmdAckFlag; // 升级文件传输指令应答标志
    public ushort u16UpgradeEndCmdAckFlag;          // 升级结束指令应答标志

    public byte u8StartProcessFlag;                 // 启动升级流程标志

    public byte u8ResendFlag;                       // 重发标志
    public byte u8ResendCnt;                        // 重发计数

    public byte u8UpdataStep;                       // 升级流程步骤
    public ushort u16DevType;                       // 设备类型

    public ushort u16WaitAckTimeCount;              // 等待应答超时计数

    public ushort u16BinFileSumFrame;               // Bin文件总帧数
    public ushort u16SendFrameMaxByte;              // 每帧最大发送字节数
    public ushort u16SendFrameNumCnt;               // 发送帧计数
    public ushort u16SendFrameByte;                 // 发送帧字节数
    public ushort u16CurrentSendFrame;              // 当前发送帧
    public uint u32SendBinFileLenCnt;               // 发送bin文件长度计数

    public uint u32BinFileLength;                   // 保存文件长度 上位机下发一包大小为1024+CRC =1026*下发包数
    public ushort u16BinFileCRC16;                  // 文件CRC16
    public uint u32BinFileCRC32;                    // 文件CRC32

    public byte u8CheckDeviceFlag;                      // 检查设备标志
    public ushort u16BootVersion;                   // Boot版本号
    public ushort u16HardwareVersion;               // 硬件版本
    public ushort u16FirmwareVersion;               // 固件版本

    public ulong u32RuningTimers;                   //运行时间

    public byte u8SendFrameFinishFlag;              // 发送帧完成标志

    public ushort u16PackMaxBytes;                  // 单包最大字节数
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1030)]
    public byte[] u8SendFileTab;                        // 文件数据缓冲区

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024000)]
    public byte[] u8BinFileTab;                        // 文件数据缓冲区

    public byte u8UpgradingFlag;                    // 正在升级标志
}

public struct _StBinfileMsg
{
    public uint u32BinFileLength;                   // 保存文件长度 上位机下发一包大小为1024+CRC =1026*下发包数
    public ushort u16BinFileCRC16;                  // 文件CRC16
    public uint u32BinFileCRC32;                    // 文件CRC32
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1030)]
    public byte[] u8FileTab;                        // 文件数据缓冲区

}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct _StSendIntoUpgradeModeMsg
{
    public byte u8ID;                      // ID
    public byte u8FunctionCode;            // 功能码
    public ushort u16StartAddr;            // 起始地址
    public ushort u16Len;                  // 数据长度
    public ushort u16IntoUpgradeModeCmd;   // 进入升级模式指令
    public ushort u16DevType;              // 设备类型
    public ushort u16Crc16;                // CRC16 校验码
};


[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct _StSendUpgradeStartMsg
{
    public byte u8ID;                       // ID
    public byte u8FunctionCode;             // 功能码
    public ushort u16StartAddr;             // 起始地址
    public ushort u16Len;                   // 数据长度
    public uint u32UpgradeBinFileLen;       // 升级文件长度
    public uint u32UpgradeBinFileCrc32;     // 升级文件CRC32校验码
    public ushort u16BinFileSumFrame;       // 文件总帧数
    public ushort u16FrameMaxByte;          // 一帧最大字节数
    public ushort u16Crc16;                 // CRC16 校验码
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct _StSendUpgradeFileTransferMsg
{
    public byte u8ID;                       // ID
    public byte u8FunctionCode;             // 功能码
    public ushort u16StartAddr;             // 起始地址
    public ushort u16Len;                   // 数据长度
    public ushort u16CurrentFrameNum;       // 当前帧号
    public ushort u16CurrentFrameDataLen;   // 当前帧数据长度
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)]
    public byte[] u8DataBuf;                // 数据
    public ushort u16Crc16;                 // CRC16 校验码

}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct _StSendUpgradeFileTransferEndCmdMsg
{
    public byte u8ID;                       // ID
    public byte u8FunctionCode;             // 功能码
    public ushort u16StartAddr;             // 起始地址
    public ushort u16Len;                   // 数据长度
    public ushort u1FileTranEndCmd;         // 文件传输结束指令
    public ushort u16Crc16;                 // CRC16 校验码
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct _StSendGetTheDeviceCmdMsg
{
    public byte u8ID;                       // ID
    public byte u8FunctionCode;             // 功能码
    public ushort u16StartAddr;             // 起始地址
    public ushort u16Len;                   // 数据长度
    public ushort u16Crc16;                 // CRC16 校验码
}

namespace win_iap_ymodem
{
    public partial class Form1 : Form
    {


        byte u8DevTypeaddr = 0x01;
        _stUartRecMsg stUartRecMsg;
        _StRS485UpgeradMsg StRS485UpgeradMsg;
        _StSendUpgradeFileTransferMsg StSendUpgradeFileTransferMsg;
        _StBinfileMsg StBinfileMsg;

        private OpenFileDialog fileDialog = new OpenFileDialog();
        private FileStream fs;

        long filelen = 0;
        long timer1sCnt = 0;
        int u8serialPortFlag = 0;
        int u16RecDataCmt = 0;
        int u16RceCnt = 0;
        int u16RceretunCnt = 0;

        int u16waitRecFlag = 0;
        int u16RectimeOutCnt = 0;

        byte[] Rxbuffer = new byte[1024];
        private bool hasOpenPort = false;
        public bool HasOpenPort
        {
            get { return hasOpenPort; }
            set
            {
                hasOpenPort = value;
                if (hasOpenPort && hasSelectBin)
                    openControlBtn();
                else
                    closeControlBtn();
            }
        }

        private bool hasSelectBin = false;
        public bool HasSelectBin
        {
            get { return hasSelectBin; }
            set
            {
                hasSelectBin = value;
                if (hasOpenPort && hasSelectBin)
                    openControlBtn();
                else
                    closeControlBtn();
            }
        }

        public static string filePath = "";

        string sendCmd = "";
        int fsLen = 0;

        const int FILE_NAME_LENGTH = 256;
        const byte FILE_SIZE_LENGTH = 16;

        private static readonly byte[] aucCRCHi = {
            0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
            0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
            0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
            0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
            0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
            0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
            0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
            0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
            0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
            0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
            0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
            0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
            0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
            0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
            0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
            0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
            0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
            0x40 };

        private static readonly byte[] aucCRCLo = {
            0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
            0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
            0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,
            0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
            0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,
            0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
            0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
            0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
            0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,
            0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
            0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
            0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
            0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,
            0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
            0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,
            0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
            0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,
            0x40 };
        /**********************************常量定义区**************************************/
        private static readonly uint[] m_CRCTable =
        {
    0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
    0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD,
    0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75,
    0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A, 0x745E66CD,
    0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039, 0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5,
    0xBE2B5B58, 0xBAEA46EF, 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D,
    0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49, 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95,
    0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1, 0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D,
    0x34867077, 0x30476DC0, 0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072,
    0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x018AEB13, 0x054BF6A4, 0x0808D07D, 0x0CC9CDCA,
    0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02,
    0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1, 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA,
    0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B, 0xBB60ADFC, 0xB6238B25, 0xB2E29692,
    0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6, 0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A,
    0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E, 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2,
    0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34, 0xDC3ABDED, 0xD8FBA05A,
    0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637, 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB,
    0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53,
    0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C, 0x3B5A6B9B,
    0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF, 0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623,
    0xF12F560E, 0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B,
    0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3,
    0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7, 0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B,
    0x9B3660C6, 0x9FF77D71, 0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3,
    0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C,
    0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24,
    0x119B4BE9, 0x155A565E, 0x18197087, 0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC,
    0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A, 0x2D15EBE3, 0x29D4F654,
    0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0, 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C,
    0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18, 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4,
    0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662, 0x933EB0BB, 0x97FFAD0C,
    0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668, 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4,
};
        /// <summary>
        /// 计算标准CRC（32位）
        /// </summary>
        private uint CalcCRCStandard(byte[] pSrc1, uint nNumberOfBytes)
        {
            uint idx;
            uint pChecksum = 0xFFFFFFFF;
            for (idx = 0; idx < nNumberOfBytes; idx++)
            {
                pChecksum = m_CRCTable[pSrc1[idx] ^ (pChecksum >> 24)] ^ (pChecksum << 8);
            }
            return pChecksum;
        }
        /// <summary>
        /// 生成CRC校验
        /// </summary>
        /// <param name="pucFrame">发送的字节数组</param>
        /// <param name="usLen">需要校验的长度</param>
        /// <returns></returns>
        private ushort CRC16(byte[] pucFrame, int usLen)
        {
            int i = 0;
            byte[] res = new byte[2] { 0xFF, 0xFF };
            ushort iIndex;
            ushort CRC = 0;
            while (usLen-- > 0)
            {
                iIndex = (ushort)(res[0] ^ pucFrame[i++]);
                res[0] = (byte)(res[1] ^ aucCRCHi[iIndex]);
                res[1] = aucCRCLo[iIndex];
            }
            CRC = (ushort)((res[1] << 8) | res[0]);
            return CRC;
        }

        System.Timers.Timer timer = new System.Timers.Timer();
        System.Timers.Timer QueryingTimer = new System.Timers.Timer();
        public Form1()
        {
            InitializeComponent();

            //1000毫秒，1秒
            timer.Interval = 3;
            timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
            timer.Start();
            QueryingTimer.Interval = 1000;
            QueryingTimer.Elapsed += new ElapsedEventHandler(QueryingTimedEvent);
            QueryingTimer.Start();

            Control.CheckForIllegalCrossThreadCalls = false;
            stUartRecMsg.u8DataBuf = new byte[2048];
            StRS485UpgeradMsg.u8SendFileTab = new byte[1024];
            StRS485UpgeradMsg.u8BinFileTab = new byte[1024000];
            StSendUpgradeFileTransferMsg.u8DataBuf = new byte[1024];

            comboBox1.SelectedIndex = comboBox1.Items.IndexOf("升级主机");
        }

        private void UpgradeSendDataProcess()
        {
            long u32Cnt = 0;
            switch (StRS485UpgeradMsg.u8UpdataStep)
            {
                case 0x00:
                    if (StRS485UpgeradMsg.u8StartProcessFlag > 0x00)
                    {
                        StRS485UpgeradMsg.u8StartProcessFlag = 0x00;

                        StRS485UpgeradMsg.u8UpdataStep = 0x01;
                        StRS485UpgeradMsg.u16WaitAckTimeCount = 0;
                        StRS485UpgeradMsg.WaitIntoUpgradeModeCmdAckFlag = 0;
                        StRS485UpgeradMsg.u16IntoUpgradeModeCmdAckFlag = 0;
                        StRS485UpgeradMsg.WaitUpgradeStartCmdAckFlag = 0;
                        StRS485UpgeradMsg.u16UpgradeStartCmdAckFlag = 0;
                        StRS485UpgeradMsg.WaitUpgradeFileTransferCmdAckFlag = 0;
                        StRS485UpgeradMsg.u16UpgradeFileTransferCmdAckFlag = 0;
                        StRS485UpgeradMsg.WaitUpgradeEndCmdAckFlag = 0;
                        StRS485UpgeradMsg.u16UpgradeEndCmdAckFlag = 0;
                        StRS485UpgeradMsg.u16SendFrameNumCnt = 0;

                        if (StRS485UpgeradMsg.u32BinFileLength % 1024 == 0x00)          //计算总帧数
                        {
                            StRS485UpgeradMsg.u16BinFileSumFrame = (ushort)(StRS485UpgeradMsg.u32BinFileLength / 1024);
                        }
                        else
                        {
                            StRS485UpgeradMsg.u16BinFileSumFrame = (ushort)(StRS485UpgeradMsg.u32BinFileLength / 1024 + 1);
                        }
                        StRS485UpgeradMsg.u16SendFrameMaxByte = 1024;                       // 每帧最大发送字节数
                    }
                    StRS485UpgeradMsg.u16PackMaxBytes = 1024;
                    break;
                case 0x01:                                                              //发送进入升级模式指令
                    if (StRS485UpgeradMsg.u16WaitAckTimeCount % 100 == 0x00)
                    {
                        SendIntoUpgradeModeCmd(StRS485UpgeradMsg.u16DevType);
                        StRS485UpgeradMsg.WaitIntoUpgradeModeCmdAckFlag = 0x01;
                        this.tbx_show.AppendText("向设备发送进入升级模式指令\r\n");//对话框追加显示数据
                    }
                    if (++StRS485UpgeradMsg.u16WaitAckTimeCount > 500)                  //等待超时判断
                    {
                        StRS485UpgeradMsg.u8UpdataStep = 0x00;
                    }
                    else if (StRS485UpgeradMsg.u16IntoUpgradeModeCmdAckFlag == 0x01)   //应答成功
                    {
                        StRS485UpgeradMsg.u8UpdataStep = 0x02;
                        StRS485UpgeradMsg.u16WaitAckTimeCount = 0;
                    }
                    else if (StRS485UpgeradMsg.u16IntoUpgradeModeCmdAckFlag == 0x02)   //应答失败
                    {
                        StRS485UpgeradMsg.u8UpdataStep = 0x00;
                    }
                    break;
                case 0x02:                                                          //发送升级开始指令
                    if (StRS485UpgeradMsg.u16WaitAckTimeCount % 200 == 0x00)
                    {
                        this.tbx_show.AppendText("向设备发送升级开始指令\r\n");//对话框追加显示数据
                        SendUpgradeStartCmd();
                        StRS485UpgeradMsg.WaitUpgradeStartCmdAckFlag = 0x01;
                    }
                    if (++StRS485UpgeradMsg.u16WaitAckTimeCount > 1000)                  //等待超时判断
                    {
                        StRS485UpgeradMsg.u8UpdataStep = 0x00;
                    }
                    else if (StRS485UpgeradMsg.u16UpgradeStartCmdAckFlag == 0x01)   //应答成功
                    {
                        StRS485UpgeradMsg.u8UpdataStep = 0x03;
                        StRS485UpgeradMsg.u16WaitAckTimeCount = 0;
                    }
                    else if (StRS485UpgeradMsg.u16UpgradeStartCmdAckFlag == 0x02)   //应答失败
                    {
                        StRS485UpgeradMsg.u8UpdataStep = 0x00;
                    }
                    break;
                case 0x03:                                                          //获取升级包步骤
                    if (StRS485UpgeradMsg.u8ResendFlag == 0)
                    {
                        StRS485UpgeradMsg.u16SendFrameNumCnt++;
                        if (StRS485UpgeradMsg.u16SendFrameNumCnt < StRS485UpgeradMsg.u16BinFileSumFrame)
                        {
                            for (u32Cnt = 0; u32Cnt < 1024; u32Cnt++)
                            {
                                StRS485UpgeradMsg.u8SendFileTab[u32Cnt] = StRS485UpgeradMsg.u8BinFileTab[(StRS485UpgeradMsg.u16SendFrameNumCnt - 1) * 1024 + u32Cnt];
                            }
                            StRS485UpgeradMsg.u16SendFrameByte = 1024;                       // 当前帧数据长度
                        }
                        else
                        {
                            if (StRS485UpgeradMsg.u32BinFileLength % 1024 == 0x00)          //计算总帧数
                            {
                                for (u32Cnt = 0; u32Cnt < 1024; u32Cnt++)
                                {
                                    StRS485UpgeradMsg.u8SendFileTab[u32Cnt] = StRS485UpgeradMsg.u8BinFileTab[(StRS485UpgeradMsg.u16SendFrameNumCnt - 1) * 1024 + u32Cnt];
                                }
                                StRS485UpgeradMsg.u16SendFrameByte = 1024;                       // 当前帧数据长度
                            }
                            else
                            {
                                StRS485UpgeradMsg.u16SendFrameByte = (ushort)(StRS485UpgeradMsg.u32BinFileLength % 1024);                       // 当前帧数据长度
                                for (u32Cnt = 0; u32Cnt < StRS485UpgeradMsg.u16SendFrameByte; u32Cnt++)
                                {
                                    StRS485UpgeradMsg.u8SendFileTab[u32Cnt] = StRS485UpgeradMsg.u8BinFileTab[(StRS485UpgeradMsg.u16SendFrameNumCnt - 1) * 1024 + u32Cnt];
                                }
                            }
                            StRS485UpgeradMsg.u8SendFrameFinishFlag = 0x01;
                            this.tbx_show.AppendText("向设备发送传输文件指令,下发文件最后一包\r\n");//对话框追加显示数据
                        }
                       ;
                    }
                    else
                    {

                    }
                    StRS485UpgeradMsg.u8UpdataStep = 0x04;
                    StRS485UpgeradMsg.u16WaitAckTimeCount = 0;
                    StRS485UpgeradMsg.WaitUpgradeFileTransferCmdAckFlag = 0;
                    StRS485UpgeradMsg.u16UpgradeFileTransferCmdAckFlag = 0;
                    break;
                case 0x04:
                    if (StRS485UpgeradMsg.u16WaitAckTimeCount % 10 == 0x00)
                    {
                        this.tbx_show.AppendText("向设备发送传输文件指令,下发文件包=" + (StRS485UpgeradMsg.u16SendFrameNumCnt).ToString() + "帧长度=" + (StRS485UpgeradMsg.u16SendFrameByte).ToString() + "\r\n");//对话框追加显示数据

                        SendUpgradeFileTransferCmd();

                        StRS485UpgeradMsg.WaitUpgradeFileTransferCmdAckFlag = 0x01;
                    }
                    StRS485UpgeradMsg.u16WaitAckTimeCount++;
                    if (StRS485UpgeradMsg.u16WaitAckTimeCount > 1000)                  //等待超时判断
                    {
                        StRS485UpgeradMsg.u8UpdataStep = 0x00;
                    }
                    else if (StRS485UpgeradMsg.u16UpgradeFileTransferCmdAckFlag == 0x01)   //应答成功
                    {
                        if (StRS485UpgeradMsg.u8SendFrameFinishFlag == 0x00)
                        {
                            StRS485UpgeradMsg.u8UpdataStep = 0x03;
                        }
                        else
                        {
                            this.tbx_show.AppendText("接收到设备最后一包数据应答\r\n");//对话框追加显示数据
                            StRS485UpgeradMsg.u8UpdataStep = 0x05;
                        }
                        StRS485UpgeradMsg.u16WaitAckTimeCount = 0;
                    }
                    else if (StRS485UpgeradMsg.u16UpgradeFileTransferCmdAckFlag == 0x02)   //应答失败
                    {
                        StRS485UpgeradMsg.u8UpdataStep = 0x00;
                    }
                    break;
                case 0x05:
                    if (StRS485UpgeradMsg.u16WaitAckTimeCount % 100 == 0x00)
                    {
                        SendUpgradeFileTransferEndCmd();
                        StRS485UpgeradMsg.WaitUpgradeEndCmdAckFlag = 0x01;
                    }
                    if (++StRS485UpgeradMsg.u16WaitAckTimeCount > 500)                  //等待超时判断
                    {
                        StRS485UpgeradMsg.u8UpdataStep = 0x00;
                    }
                    else if (StRS485UpgeradMsg.u16UpgradeEndCmdAckFlag == 0x01)   //应答成功
                    {
                        StRS485UpgeradMsg.u8UpdataStep = 0x00;
                        StRS485UpgeradMsg.u16WaitAckTimeCount = 0;
                    }
                    else if (StRS485UpgeradMsg.u16UpgradeEndCmdAckFlag == 0x02)   //应答失败
                    {
                        StRS485UpgeradMsg.u8UpdataStep = 0x00;
                    }
                    break;
                default: break;
            }
        }
        private void UartDataRecPro(_stUartRecMsg stGetMsg)
        {
            ushort u16CuCrc16;
            ushort u16GetCrc16;
            ushort u16GetStartAddr = 0;
            ushort u16FuntiongCode = 0;
            if (stGetMsg.u16len < 0x05)
            {
                return;
            }
            if (stGetMsg.u8DataBuf[0] != 0x01)
            {
                return;
            }
            u16FuntiongCode = stGetMsg.u8DataBuf[1];
            u16CuCrc16 = CRC16(stGetMsg.u8DataBuf, stGetMsg.u16len - 2); // 计算CRC
            u16GetCrc16 = (ushort)(stGetMsg.u8DataBuf[stGetMsg.u16len - 1] * 256 + stGetMsg.u8DataBuf[stGetMsg.u16len - 2]);
            if (u16CuCrc16 != u16GetCrc16)
            {
                return;
            }
            u16GetStartAddr = (ushort)(stGetMsg.u8DataBuf[2] * 256 + stGetMsg.u8DataBuf[3]);
            if (u16FuntiongCode == 0x0010)
            {
                switch (u16GetStartAddr)
                {
                    case 0x8500:
                        if (stGetMsg.u8DataBuf[6] == 0x00 && stGetMsg.u8DataBuf[7] == 0xAA)
                        {
                            if (StRS485UpgeradMsg.WaitIntoUpgradeModeCmdAckFlag == 0x01)
                            {
                                StRS485UpgeradMsg.u16IntoUpgradeModeCmdAckFlag = 0x01;
                            }
                        }
                        break;
                    case 0x8305:
                        if (stGetMsg.u8DataBuf[6] == 0x00 && stGetMsg.u8DataBuf[7] == 0xAA)
                        {
                            if (StRS485UpgeradMsg.WaitUpgradeStartCmdAckFlag == 0x01)
                            {
                                StRS485UpgeradMsg.u16UpgradeStartCmdAckFlag = 0x01;
                            }
                        }
                        break;
                    case 0x8320:
                        if (stGetMsg.u8DataBuf[6] == 0x00 && stGetMsg.u8DataBuf[7] == 0xAA)
                        {
                            if (StRS485UpgeradMsg.WaitUpgradeFileTransferCmdAckFlag == 0x01)
                            {
                                StRS485UpgeradMsg.u16UpgradeFileTransferCmdAckFlag = 0x01;
                            }
                        }
                        break;
                    case 0x9520:
                        if (stGetMsg.u8DataBuf[6] == 0x00 && stGetMsg.u8DataBuf[7] == 0xAA)
                        {
                            if (StRS485UpgeradMsg.WaitUpgradeEndCmdAckFlag == 0x01)
                            {
                                StRS485UpgeradMsg.u16UpgradeEndCmdAckFlag = 0x01;
                            }
                        }
                        break;
                    default: break;
                }
            }
            else if (u16FuntiongCode == 0x0015)
            {

                u16GetStartAddr = (ushort)(stGetMsg.u8DataBuf[2] * 256 + stGetMsg.u8DataBuf[3]);
                //u16length = (ushort)(stGetMsg.u8DataBuf[4] * 256 + stGetMsg.u8DataBuf[5]);
                StRS485UpgeradMsg.u16DevType = (ushort)(stGetMsg.u8DataBuf[6] * 256 + stGetMsg.u8DataBuf[7]);              // 硬件版本
                StRS485UpgeradMsg.u16HardwareVersion = (ushort)(stGetMsg.u8DataBuf[8] * 256 + stGetMsg.u8DataBuf[9]);               // 固件版本
                StRS485UpgeradMsg.u16FirmwareVersion = (ushort)(stGetMsg.u8DataBuf[10] * 256 + stGetMsg.u8DataBuf[11]);                      // 设备类型
                StRS485UpgeradMsg.u32RuningTimers = (ushort)(stGetMsg.u8DataBuf[12] * 256 + stGetMsg.u8DataBuf[13]);
                textBox1.Text = StRS485UpgeradMsg.u16HardwareVersion.ToString();
                textBox2.Text = StRS485UpgeradMsg.u16FirmwareVersion.ToString();
                textBox3.Text = StRS485UpgeradMsg.u32RuningTimers.ToString();
            }
        }

        private void OnTimedEvent(object sender, ElapsedEventArgs e)
        {
            if (u8serialPortFlag != 0x01)
            {
                return;
            }
            UpgradeSendDataProcess();//升级发送流程
            u16RectimeOutCnt++;
            if (u16RectimeOutCnt > 1)
            {
                u16RectimeOutCnt = 0;
                if (stUartRecMsg.u16len > 0)
                {
                    u16RceCnt++;
                    UartDataRecPro(stUartRecMsg);//处理串口数据
                    //this.tbx_show.AppendText("接收数据" + (u16RceCnt).ToString() + "\r\n");//对话框追加显示数据
                    stUartRecMsg.u16len = 0;
                }
            }
        }

        private void QueryingTimedEvent(object sender, ElapsedEventArgs e)
        {
            if ((u8serialPortFlag != 0x01) || (StRS485UpgeradMsg.u8UpdataStep != 0))
            {
                return;
            }
            if (StRS485UpgeradMsg.u8CheckDeviceFlag == 0x01)
            {
                SendGetTheDeviceCmd();
                StRS485UpgeradMsg.u8CheckDeviceFlag = 0;
            }
        }

        private ushort Swap161(ushort value)
        {
            return (ushort)((value >> 8) | (value << 8));
        }

        // 交换32位字节序
        private uint Swap321(uint value)
        {
            return (uint)((value >> 24) | ((value >> 8) & 0xFF00) | ((value << 8) & 0xFF0000) | (value << 24));
        }
        //-----------------------------------------------------------
        //Description    : 发送进入升级模式命令
        //Input          : None
        //Output         : None
        //Author         : C7
        //Note(s)        : None
        //-----------------------------------------------------------
        private void SendIntoUpgradeModeCmd(ushort u16DevType)
        {
            _StSendIntoUpgradeModeMsg StSendIntoUpgradeModeMsg = new _StSendIntoUpgradeModeMsg
            {
                u8ID = u8DevTypeaddr,
                u8FunctionCode = 0x10,
                u16StartAddr = Swap161(0x8500),
                u16Len = Swap161(0x0002),
                u16IntoUpgradeModeCmd = Swap161(0x55AA),
                u16DevType = Swap161(u16DevType),
                u16Crc16 = 0 // 初始值设置为0，稍后计算
            };
            int size = Marshal.SizeOf(typeof(_StSendIntoUpgradeModeMsg));                           //获取结构体大小
            IntPtr ptr = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(StSendIntoUpgradeModeMsg, ptr, false);                          // 将结构体复制到内存
            byte[] byteArray = new byte[size];                                                      // 创建字节数组
            Marshal.Copy(ptr, byteArray, 0, size);                                                  // 将内存中的数据复制到字节数组
            StSendIntoUpgradeModeMsg.u16Crc16 = CRC16(byteArray, Marshal.SizeOf(typeof(_StSendIntoUpgradeModeMsg)) - 2); // 计算CRC
            byteArray[size - 2] = (byte)(StSendIntoUpgradeModeMsg.u16Crc16 & 0xFF);                // 低字节
            byteArray[size - 1] = (byte)((StSendIntoUpgradeModeMsg.u16Crc16 >> 8) & 0xFF);         // 高字节
            serialPort1.Write(byteArray, 0, size);                                                  //串口发送
        }
        //-----------------------------------------------------------
        //Description    : 发送升级开始命令
        //Input          : None
        //Output         : None
        //Author         : C7
        //Note(s)        : None
        //-----------------------------------------------------------
        private void SendUpgradeStartCmd()
        {
            _StSendUpgradeStartMsg StSendUpgradeStartMsg = new _StSendUpgradeStartMsg
            {
                u8ID = 0x01,                                                                        // ID
                u8FunctionCode = 0x10,                                                              // 功能码
                u16StartAddr = Swap161(0x8305),                                                     // 起始地址
                u16Len = Swap161(0x000C),                                                           // 数据长度
                u32UpgradeBinFileLen = Swap321((uint)(StRS485UpgeradMsg.u32BinFileLength)),                 // 升级文件长度
                u32UpgradeBinFileCrc32 = Swap321((uint)StRS485UpgeradMsg.u32BinFileCRC32),                // 升级文件CRC32校验码
                u16BinFileSumFrame = Swap161(StRS485UpgeradMsg.u16BinFileSumFrame),                 // 文件总帧数
                u16FrameMaxByte = Swap161(StRS485UpgeradMsg.u16PackMaxBytes),                       // 一帧最大字节数
                u16Crc16 = 0,                                                                       // CRC16 校验码
            };
            int size = Marshal.SizeOf(typeof(_StSendUpgradeStartMsg));                           //获取结构体大小
            IntPtr ptr = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(StSendUpgradeStartMsg, ptr, false);                              // 将结构体复制到内存
            byte[] byteArray = new byte[size];                                                      // 创建字节数组
            Marshal.Copy(ptr, byteArray, 0, size);                                                  // 将内存中的数据复制到字节数组
            StSendUpgradeStartMsg.u16Crc16 = CRC16(byteArray, Marshal.SizeOf(typeof(_StSendUpgradeStartMsg)) - 2); // 计算CRC
            byteArray[size - 2] = (byte)(StSendUpgradeStartMsg.u16Crc16 & 0xFF);                    // 低字节
            byteArray[size - 1] = (byte)((StSendUpgradeStartMsg.u16Crc16 >> 8) & 0xFF);             // 高字节
            serialPort1.Write(byteArray, 0, size);                                                  //串口发送
        }

        //-----------------------------------------------------------
        //Description    : 发送文件传输命令
        //Input          : None
        //Output         : None
        //Author         : C7
        //Note(s)        : None
        //-----------------------------------------------------------
        private void SendUpgradeFileTransferCmd()
        {
            UInt16 u16Cnt;
            StSendUpgradeFileTransferMsg.u8ID = 0x01;                                                                          // ID
            StSendUpgradeFileTransferMsg.u8FunctionCode = 0x10;                                                                // 功能码
            StSendUpgradeFileTransferMsg.u16StartAddr = Swap161(0x8320);                                                       // 起始地址
            StSendUpgradeFileTransferMsg.u16Len = Swap161((ushort)(StRS485UpgeradMsg.u16SendFrameByte + 4));
            StSendUpgradeFileTransferMsg.u16CurrentFrameNum = Swap161(StRS485UpgeradMsg.u16SendFrameNumCnt);                     // 数据长度
            StSendUpgradeFileTransferMsg.u16CurrentFrameDataLen = Swap161(StRS485UpgeradMsg.u16SendFrameByte);                 // 数据长度
            for (u16Cnt = 0x00; u16Cnt < StRS485UpgeradMsg.u16SendFrameByte; u16Cnt++)
            {
                StSendUpgradeFileTransferMsg.u8DataBuf[u16Cnt] = StRS485UpgeradMsg.u8SendFileTab[u16Cnt];
            }
            int size = Marshal.SizeOf(typeof(_StSendUpgradeFileTransferMsg));                                               //获取结构体大小
            IntPtr ptr = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(StSendUpgradeFileTransferMsg, ptr, false);                                                  // 将结构体复制到内存
            byte[] byteArray = new byte[size];                                                                          // 创建字节数组
            Marshal.Copy(ptr, byteArray, 0, size);                                                                      // 将内存中的数据复制到字节数组
            StSendUpgradeFileTransferMsg.u16Crc16 = CRC16(byteArray, StRS485UpgeradMsg.u16SendFrameByte + 10);                        // 计算CRC
            byteArray[StRS485UpgeradMsg.u16SendFrameByte + 10] = (byte)(StSendUpgradeFileTransferMsg.u16Crc16 & 0xFF);             // 低字节
            byteArray[StRS485UpgeradMsg.u16SendFrameByte + 10 + 1] = (byte)((StSendUpgradeFileTransferMsg.u16Crc16 >> 8) & 0xFF);     // 高字节
            timer.Stop();
            serialPort1.Write(byteArray, 0, StRS485UpgeradMsg.u16SendFrameByte + 12);                                            //串口发送
            timer.Start();

        }
        //-----------------------------------------------------------
        //Description    : 发送文件传输结束命令
        //Input          : None
        //Output         : None
        //Author         : C7
        //Note(s)        : None
        //-----------------------------------------------------------
        private void SendUpgradeFileTransferEndCmd()
        {
            _StSendUpgradeFileTransferEndCmdMsg StSendUpgradeFileTransferEndCmdMsg = new _StSendUpgradeFileTransferEndCmdMsg
            {
                u8ID = 0x01,
                u8FunctionCode = 0x10,
                u16StartAddr = Swap161(0x9520),
                u16Len = Swap161(0x0002),
                u1FileTranEndCmd = Swap161(0x55AA),
                u16Crc16 = 0 // 初始值设置为0，稍后计算
            };
            int size = Marshal.SizeOf(typeof(_StSendUpgradeFileTransferEndCmdMsg));                           //获取结构体大小
            IntPtr ptr = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(StSendUpgradeFileTransferEndCmdMsg, ptr, false);                          // 将结构体复制到内存
            byte[] byteArray = new byte[size];                                                      // 创建字节数组
            Marshal.Copy(ptr, byteArray, 0, size);                                                  // 将内存中的数据复制到字节数组
            StSendUpgradeFileTransferEndCmdMsg.u16Crc16 = CRC16(byteArray, Marshal.SizeOf(typeof(_StSendUpgradeFileTransferEndCmdMsg)) - 2); // 计算CRC
            byteArray[size - 2] = (byte)(StSendUpgradeFileTransferEndCmdMsg.u16Crc16 & 0xFF);                // 低字节
            byteArray[size - 1] = (byte)((StSendUpgradeFileTransferEndCmdMsg.u16Crc16 >> 8) & 0xFF);         // 高字节
            serialPort1.Write(byteArray, 0, size);                                                  //串口发送
        }

        public void SendGetTheDeviceCmd()
        {
            _StSendGetTheDeviceCmdMsg StSendGetTheDeviceCmdMsg = new _StSendGetTheDeviceCmdMsg
            {
                u8ID = 0x01,
                u8FunctionCode = 0x15,
                u16StartAddr = Swap161(0x1400),
                u16Len = Swap161(0x0008),
                u16Crc16 = 0 // 初始值设置为0，稍后计算
            };
            int size = Marshal.SizeOf(typeof(_StSendGetTheDeviceCmdMsg));
            IntPtr ptr = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(StSendGetTheDeviceCmdMsg, ptr, false);
            byte[] byteArray = new Byte[size];
            Marshal.Copy(ptr, byteArray, 0, size);
            StSendGetTheDeviceCmdMsg.u16Crc16 = CRC16(byteArray, Marshal.SizeOf(typeof(_StSendGetTheDeviceCmdMsg)) - 2);
            byteArray[size - 2] = (byte)(StSendGetTheDeviceCmdMsg.u16Crc16 & 0xFF);
            byteArray[size - 1] = (byte)((StSendGetTheDeviceCmdMsg.u16Crc16 >> 8) & 0xFF);
            serialPort1.Write(byteArray, 0, size);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            closeControlBtn();
            EnumComportfromReg(cbx_Port);
            serialPort1.Encoding = Encoding.GetEncoding("gb2312");//串口接收编码GB2312码
            System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;//忽略程序跨越线程运行导致的错误.没有此句将会产生错误
            cbx_Baud.SelectedIndex = 13;
            cbx_PageSize.SelectedIndex = 4;
        }

        /// <summary>
        /// enabled all button
        /// </summary>
        private void openControlBtn()
        {

            btn_Upload.Enabled = true;
            //btn_Erase.Enabled = true;
        }


        /// <summary>
        /// disabled all button
        /// </summary>
        private void closeControlBtn()
        {
            btn_Upload.Enabled = false;
            //btn_Erase.Enabled = false;

        }

        /// <summary>
        /// the button for select bin file or hex file.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_SelectFile_Click(object sender, EventArgs e)
        {
            // openFileDialog1.ShowDialog();
            OpenFileDialog fileDialog = new OpenFileDialog();
            //设置初始目录
            fileDialog.InitialDirectory = @"";
            fileDialog.Title = "请选择要发送的文件";
            //过滤文件类型
            fileDialog.Filter = "bin文件|*.bin";

            int u16len = 0;
            long filelen = 0;
            long u32Cnt = 0;
            //fileDialog.ShowDialog();
            //将选择的文件的全路径赋值给文本框

            fileDialog.Multiselect = true;

            if (fs != null)
            {
                fs.Close();
            }

            if (fileDialog.ShowDialog() == DialogResult.OK)
            {
                fs = new FileStream(fileDialog.FileName, FileMode.Open);
                if (fs.Length > 2 * 1024)
                {       //文件大小必须大于2k
                    StRS485UpgeradMsg.u32BinFileLength = (uint)fs.Length;//文件长度
                    Array.Clear(StRS485UpgeradMsg.u8BinFileTab, 0, 1024000);//先清空上次的缓存内容
                    fs.Read(StRS485UpgeradMsg.u8BinFileTab, 0, (int)fs.Length);
                    this.tbx_show.AppendText("打开文件\r\n");//对话框追加显示数据
                    this.tbx_show.AppendText(fs.Name);//对话框追加显示数据
                    this.tbx_show.AppendText("\r\n文件大小:");//对话框追加显示数据
                    this.tbx_show.AppendText((fs.Length).ToString());//对话框追加显示数据
                    this.tbx_show.AppendText("kb\r\n");//对话框追加显示数据
                    //this.txb_FilePath.Text = fileDialog.FileName;
                    this.txb_FilePath.Text = fs.Name;

                    StRS485UpgeradMsg.u32BinFileCRC32 = CalcCRCStandard(StRS485UpgeradMsg.u8BinFileTab, StRS485UpgeradMsg.u32BinFileLength);
                    this.tbx_show.AppendText("Crc32=" + (StRS485UpgeradMsg.u32BinFileCRC32).ToString());//对话框追加显示数据

                }
                else
                {
                    this.tbx_show.AppendText("打开文件\r\n");//对话框追加显示数据
                    this.tbx_show.AppendText(fs.Name);//对话框追加显示数据
                    this.tbx_show.AppendText("\r\n文件大小:");//对话框追加显示数据
                    this.tbx_show.AppendText((fs.Length / 1024.0).ToString());//对话框追加显示数据
                    this.tbx_show.AppendText("kb\r\n");//对话框追加显示数据
                    this.tbx_show.AppendText("打开文件异常\r\n");//对话框追加显示数据
                    this.tbx_show.Text = "APP文件打开失败";
                }
            }
        }


        /// <summary>
        /// has been selected the right file.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void openFileDialog1_FileOk(object sender, CancelEventArgs e)
        {
            filePath = openFileDialog1.FileName;
            //Get the extension of the file
            string extName = Path.GetExtension(filePath);
            if (extName == ".hex")
            {
                //we shoule convert the hex file to bin file.
                if (HexToBin.convertHexToBin(filePath))
                {
                    tbx_show.AppendText("> 文件转换完成!\r\n");
                }
                else
                {
                    tbx_show.AppendText("> 文件转换失败!\r\n");
                }
            }

            txb_FilePath.Text = filePath;

            HasSelectBin = true;//flag has been select file.

            FileStream fileStream = new FileStream(@filePath, FileMode.Open, FileAccess.Read);
            fsLen = (int)fileStream.Length;
            tbx_show.AppendText("文件大小: " + fsLen.ToString() + "\r\n");
        }


        /// <summary>
        /// get all port and add to cbx_Port.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cbx_Port_DropDown(object sender, EventArgs e)
        {
            if (!HasOpenPort)
            {
                EnumComportfromReg(cbx_Port);
            }
        }


        /// <summary>
        /// open or close port.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_Port_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen)//try to close
            {
                try
                {
                    serialPort1.Close();
                    btn_Port.Text = "打开";
                    HasOpenPort = false;

                }
                catch (Exception ex)
                {
                    MessageBox.Show("关闭失败");
                    return;
                }
            }
            else //try to open
            {
                if (cbx_Port.Items.Count == 0)
                    return;
                int baud = int.Parse(cbx_Baud.Text);
                serialPort1.PortName = cbx_Port.Text;
                serialPort1.BaudRate = baud;
                serialPort1.WriteBufferSize = 2048;
                serialPort1.Encoding = Encoding.UTF8;
                try
                {
                    serialPort1.Open();
                    btn_Port.Text = "关闭";
                    HasOpenPort = true;
                    u8serialPortFlag = 0x01;
                    openControlBtn();
                }
                catch (Exception ex)
                {
                    MessageBox.Show("打开失败");
                    return;
                }
            }
        }


        /// <summary>
        /// Get the port list from the registry
        /// </summary>
        /// <param name="Combobox"></param>
        private void EnumComportfromReg(ComboBox Combobox)
        {
            Combobox.Items.Clear();
            ///定义注册表子Path
            string strRegPath = @"Hardware\\DeviceMap\\SerialComm";
            ///创建两个RegistryKey类，一个将指向Root Path，另一个将指向子Path
            RegistryKey regRootKey;
            RegistryKey regSubKey;
            ///定义Root指向注册表HKEY_LOCAL_MACHINE节点
            regRootKey = Registry.LocalMachine;
            regSubKey = regRootKey.OpenSubKey(strRegPath);
            if (regSubKey.GetValueNames() == null)
            {
                MessageBox.Show("获取串口设备失败");
                return;
            }
            string[] strCommList = regSubKey.GetValueNames();
            foreach (string VName in strCommList)
            {
                //向listbox1中添加字符串的名称和数据，数据是从rk对象中的GetValue(it)方法中得来的
                Combobox.Items.Add(regSubKey.GetValue(VName));
            }
            if (Combobox.Items.Count > 0)
            {
                Combobox.SelectedIndex = 0;
            }
            else
            {
                Combobox.Text = "";
            }
            regSubKey.Close();
            regRootKey.Close();
        }


        /// <summary>
        /// 打印接收到的16进制数据
        /// </summary>
        /// <param name="data">接收到的字节数组</param>
        private void PrintHexData(byte[] data)
        {
            if (data == null || data.Length == 0)
            {
                tbx_show.AppendText("接收到空数据\r\n");
                return;
            }

            StringBuilder sb = new StringBuilder();
            foreach (byte b in data)
            {
                sb.Append(b.ToString("X2") + " ");
            }

            tbx_show.AppendText("接收到的数据: " + sb.ToString().Trim() + "\r\n");
        }

        /// <summary>
        /// once has date in. we should show it on the txb.(找到了bug的原因，就是有数据来了之后首先主动去读取了一次数据，然后又通过这个服务去被动读取了一次，所以会出现问题。)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            int u16cnt = 0;
            byte[] buffer = new byte[1024];
            u16RceretunCnt = serialPort1.Read(buffer, 0, buffer.Length);
            if (u16RceretunCnt > 0)
            {
                for (u16cnt = stUartRecMsg.u16len; u16cnt < (stUartRecMsg.u16len + u16RceretunCnt); u16cnt++)
                {
                    stUartRecMsg.u8DataBuf[u16cnt] = buffer[u16cnt];
                }
                stUartRecMsg.u16len += u16RceretunCnt;
                u16RectimeOutCnt = 0;
            }

        }


        /// <summary>
        /// A thread to update firmware.
        /// </summary>
        private void updateFileThread()
        {

        }

        /// <summary>
        /// erase all flash when the button has checked.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_Erase_Click(object sender, EventArgs e)
        {
            StRS485UpgeradMsg.u8CheckDeviceFlag = 0x01;
        }

        /// <summary>
        /// upload the app file form stm32 to PC.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_Upload_Click(object sender, EventArgs e)
        {

            StRS485UpgeradMsg.u8StartProcessFlag = 0x01;


        }

        /// <summary>
        /// reset the stm32 when the button has been checkde.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_Reset_Click(object sender, EventArgs e)
        {
            serialPort1.Write("reset\r\n");
        }


        /// <summary>
        /// clear tbx_show window when the button has been checked.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_Clear_Click(object sender, EventArgs e)
        {
            tbx_show.Text = "";
        }



        /// <summary>
        /// when user is input the key on the tbx_show, it should be send to stm32.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tbx_show_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)Keys.Enter)
            {
                //tbx_show.AppendText("\r\n" + sendCmd + "\r\n");
                switch (sendCmd)
                {
                    case "upload":
                        btn_Upload_Click(null, null);
                        break;
                    case "erase":
                        btn_Erase_Click(null, null);
                        break;
                    default:
                        serialPort1.Write(sendCmd + "\r\n");
                        break;
                }
                sendCmd = "";
            }
            else if (e.KeyChar == (char)Keys.Back)
            {
                if (sendCmd.Length > 0)
                    sendCmd = sendCmd.Substring(0, sendCmd.Length - 1);
            }
            else
            {
                sendCmd += e.KeyChar.ToString();
            }
        }


        private byte getPageHead(string text)
        {
            switch (Convert.ToInt32(text))
            {
                //case 8:
                //    return 0xA1;
                //case 16:
                //    return 0xA2;
                case 32:
                    return 0xA3;
                case 64:
                    return 0xA4;
                case 128:
                    return 0xA5;
                case 256:
                    return 0xA6;
                case 512:
                    return 0xA7;
                case 1024:
                    return 0xA8;
                //case 2048:
                //    return 0xA9;
                default:
                    return 2;
            }
        }


        private byte[] CalculateFileCrc32(FileStream fileStream)
        {
            using (var crc32 = new Crc32())
            {
                fileStream.Seek(0, SeekOrigin.Begin);
                return crc32.ComputeHash(fileStream);
            }
        }

        public class Crc32 : HashAlgorithm, IDisposable
        {
            private uint _hash;
            private static readonly uint[] _table;

            static Crc32()
            {
                _table = new uint[256];
                const uint polynomial = 0xEDB88320;
                for (uint i = 0; i < 256; i++)
                {
                    uint crc = i;
                    for (int j = 8; j > 0; j--)
                    {
                        if ((crc & 1) == 1)
                            crc = (crc >> 1) ^ polynomial;
                        else
                            crc >>= 1;
                    }
                    _table[i] = crc;
                }
            }

            public Crc32()
            {
                _hash = 0xFFFFFFFF;
                Initialize();
            }

            public override void Initialize()
            {
                _hash = 0xFFFFFFFF;
            }

            protected override void HashCore(byte[] array, int ibStart, int cbSize)
            {
                uint crc = _hash;
                for (int i = ibStart; i < ibStart + cbSize; i++)
                {
                    byte index = (byte)((crc ^ array[i]) & 0xFF);
                    crc = (crc >> 8) ^ _table[index];
                }
                _hash = crc;
            }

            protected override byte[] HashFinal()
            {
                var hashBuffer = new byte[4];
                var hash = _hash ^ 0xFFFFFFFF;
                hashBuffer[0] = (byte)(hash & 0xFF);
                hashBuffer[1] = (byte)((hash >> 8) & 0xFF);
                hashBuffer[2] = (byte)((hash >> 16) & 0xFF);
                hashBuffer[3] = (byte)((hash >> 24) & 0xFF);
                return hashBuffer;
            }

            public override int HashSize => 32;

            // 实现 IDisposable 接口
            public new void Dispose()
            {
                // 释放资源
                GC.SuppressFinalize(this);
            }
        }

        private void tbx_show_TextChanged(object sender, EventArgs e)
        {

        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (comboBox1.SelectedItem.ToString()) //获取选择的内容
            {

                case "升级主机": StRS485UpgeradMsg.u16DevType = 0x0000; break;

                case "升级从机": StRS485UpgeradMsg.u16DevType = 0x0001; break;

                case "全部升级": StRS485UpgeradMsg.u16DevType = 0x0002; break;

            }
        }
    }
}
